<?php
declare(strict_types=1);

namespace App\Chat\Controller\Talk;

use App\Chat\Annotation\ChatAuth;
use App\Chat\Cache\LastMessage;
use App\Chat\Cache\Repository\LockRedis;
use App\Chat\Cache\UnreadTalkCache;
use App\Chat\Constant\TalkModeConstant;
use App\Chat\Controller\ChatBaseController;
use App\Chat\Request\TalkRequest;
use App\Chat\Service\TalkSessionService;
use App\Chat\Service\UserFriendService;
use App\Chat\Support\UserRelation;
use App\CustHub\Model\ChContact;
use App\CustHub\Model\ChRoom;
use App\CustHub\Model\ChTalkSession;
use App\CustHub\Service\ChCustomerServiceService;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\PostMapping;
use Hyperf\HttpServer\Annotation\RequestMapping;
use Psr\Http\Message\ResponseInterface;

#[Controller('ch/chat/talk'),ChatAuth]
class TalkController extends ChatBaseController
{

    #[Inject]
    protected TalkSessionService $talkSessionService;

    #[Inject]
    protected ChCustomerServiceService $service;


    /**
     * 获取机器人列表
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping("getRobotList")]
    public function getRobotList(): ResponseInterface
    {
        return $this->success($this->service->getRobotList($this->request->all()));
    }

    /**
     * 获取用户对话列表
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('list')]
    public function list(TalkRequest $request): ResponseInterface
    {
        $user_id = $this->uid();
        $data = $request->all();
        $robotId = $data['robot_id'] ?? 0;
        $keyword = $data['keyword'] ?? '';
        $type = (int)$data['type'] ?? 0;
        $pageSize = $data['page_size'] ?? 10;
        return $this->success($this->talkSessionService->getTalkList($robotId,$user_id,$type,$keyword,(int) $pageSize));
    }

    /**
     * 新增对话列表
     * @param UserFriendService $service
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('create')]
    public function create(UserFriendService $service): ResponseInterface
    {
        $params = $this->request->inputs(['talk_type', 'robot_id', 'receiver_id']);

        $this->validate($params, [
            'talk_type'   => 'required|in:1,2',
            'receiver_id' => 'required|integer|min:1',
            'robot_id' => 'required|integer'
        ]);

        $user_id = $this->uid();
        $robotId = (int)$params['robot_id'];
        $receiverId = (int)$params['receiver_id'];
        $talk_type = (int)$params['talk_type'];
        $string  = join('-', [$user_id, $receiverId, $talk_type, md5($this->request->getHeaderLine('user-agent'))]);
        $lock    = 'talk:list:' . $string;

        // 防止前端并发请求
        if (!LockRedis::getInstance()->lock($lock, 60)) {
            return $this->response->error('创建失败1！');
        }

        if (!UserRelation::isFriendOrGroupMember($user_id, $robotId,$receiverId, $talk_type)) {
            LockRedis::getInstance()->delete($lock);
            return $this->error('暂不属于好友关系或群聊成员，无法进行聊天！');
        }

        $result = $this->talkSessionService->create(1,$robotId,$user_id, $receiverId, $talk_type);
        if (!$result) {
            LockRedis::getInstance()->delete($lock);
            return $this->response->fail('创建失败2！');
        }

        $data = ChTalkSession::item([
            'id'          => $result['id'],
            'talk_type'   => $talk_type,
            'robot_id'    => $robotId,
            'receiver_id' => $receiverId,
        ]);

        if ($talk_type == TalkModeConstant::PRIVATE_CHAT) {
            $userInfo            = ChContact::query()->where('id', $receiverId)->first(['nickname', 'avatar','remark']);
            $data['avatar']      = $userInfo->avatar;
            $data['name']        = $userInfo->nickname;
            $data['unread_num']  = UnreadTalkCache::getInstance()->read($user_id,$robotId, $receiverId, $user_id);
            $data['remark_name'] = $userInfo->remark;
        } else if ($talk_type == TalkModeConstant::GROUP_CHAT) {
            $groupInfo      = ChRoom::query()->where('id', $receiverId)->first(['room_name', 'room_avatar_url']);
            $data['name']   = $groupInfo->room_name;
            $data['avatar'] = $groupInfo->room_avatar_url;
        }

        $records = LastMessage::getInstance()->read($talk_type, $user_id, $receiverId);
        if ($records) {
            $data['msg_text']   = $records['text'];
            $data['updated_at'] = $records['created_at'];
        }

        return $this->success($data);
    }

    /**
     * 删除对话列表
     */
    #[PostMapping('delete')]
    public function delete(): ResponseInterface
    {
        $params = $this->request->inputs(['id']);
        $this->validate($params, [
            'id' => 'required|integer|min:0'
        ]);

        return $this->talkSessionService->deleteSession($this->uid(), (int)$params['id'])
            ? $this->success( '对话列表删除成功...')
            : $this->error('对话列表删除失败！');
    }

    /**
     * 对话列表置顶
     */
    #[PostMapping('topping')]
    public function topping(): ResponseInterface
    {
        $params = $this->request->inputs(['id', 'type']);

        $this->validate($params, [
            'id' => 'required|integer|min:0',
            'type'    => 'required|in:0,1',
        ]);

        return $this->talkSessionService->change($this->uid(), (int)$params['id'], $params['type'] == 1,'is_top')
            ? $this->success('操作成功')
            : $this->error('操作失败');
    }

    #[PostMapping('disturb')]
    public function disturb(): ResponseInterface
    {
        $params = $this->request->inputs(['id', 'type']);

        $this->validate($params, [
            'id' => 'required|integer|min:0',
            'type'    => 'required|in:0,1',
        ]);
        $rst = $this->talkSessionService->change($this->uid(),(int)$params['id'], $params['type'] == 1,'is_disturb');
        return $rst ? $this->success('操作成功') : $this->error('操作失败');
    }

    #[PostMapping('pending')]
    public function pending(): ResponseInterface
    {
        $params = $this->request->inputs(['id', 'type']);

        $this->validate($params, [
            'id' => 'required|integer|min:0',
            'type'    => 'required|in:0,1',
        ]);
        $rst = $this->talkSessionService->change($this->uid(),(int)$params['id'], $params['type'] == 1,'is_pending');
        return $rst ? $this->success('操作成功') : $this->error('操作失败');
    }

    #[PostMapping('hidden')]
    public function hidden(): ResponseInterface
    {
        $params = $this->request->inputs(['id', 'type']);

        $this->validate($params, [
            'id' => 'required|integer|min:0',
            'type'    => 'required|in:0,1',
        ]);
        $rst = $this->talkSessionService->change($this->uid(),(int)$params['id'], $params['type'] == 1,'is_hidden');
        return $rst ? $this->success('操作成功') : $this->error('操作失败');
    }

    #[PostMapping('blocked')]
    public function blocked(): ResponseInterface
    {
        $params = $this->request->inputs(['id', 'type']);

        $this->validate($params, [
            'id' => 'required|integer|min:0',
            'type'    => 'required|in:0,1',
        ]);
        $rst = $this->talkSessionService->change($this->uid(),(int)$params['id'], $params['type'] == 1,'is_blocked');
        return $rst ? $this->success('操作成功') : $this->error('操作失败');
    }

    /**
     * 标记为已读/未读
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('unread')]
    public function unread(): ResponseInterface
    {
        $params = $this->request->inputs(['id', 'type']);

        $this->validate($params, [
            'id' => 'required|integer|min:0',
            'type'    => 'required|in:0,1',
        ]);

        $info = ChTalkSession::query()
            ->where('id', $params['id'])
            ->where('user_id', $this->uid())
            ->first();
        if(!$info){
            return $this->error('操作失败');
        }
        UnreadTalkCache::getInstance()->reset($this->uid(),$info->robot_id,$info->talk_type, $info->receiver_id);

        try {
            $this->talkSessionService->reset($info->id);
        }catch (\Throwable $e){
            stdout_log()->info('清空未读消息失败');
        }
        if($params['type'] == 0){
            //标记为未读
            UnreadTalkCache::getInstance()->increment($info->user_id,$info->robot_id,$info->talk_type,$info->receiver_id);
            try {
                $this->talkSessionService->increment($info->id);
            }catch (\Throwable $e){
                stdout_log()->info('缓存未读消息数量失败');
            }
        }
        return $this->success();
    }

    /**
     * 更新对话列表未读数
     */
    #[PostMapping('unread/clear')]
    public function updateUnreadNum(): ResponseInterface
    {
        $params = $this->request->inputs(['talk_type', 'robot_id', 'receiver_id']);

        $this->validate($params, [
            'talk_type'   => 'required|in:1,2',
            'robot_id' => 'required',
            'receiver_id' => 'required|integer|min:1',
        ]);

        // 设置好友消息未读数
        UnreadTalkCache::getInstance()->reset($this->uid(),$params['robot_id'],(int)$params['talk_type'], $params['receiver_id']);
        try {
            ChTalkSession::query()
                ->where('user_id', $this->uid())
                ->where('robot_id', $params['robot_id'])
                ->where('talk_type', $params['talk_type'])
                ->where('receiver_id', $params['receiver_id'])
                ->update(['unread_num' => 0]);

        }catch (\Throwable $e){
            stdout_log()->info('清空未读消息失败');
        }
        return $this->success();
    }

    /**
     * 下载文件
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('download')]
    public function download(): ResponseInterface
    {
        $params = $this->request->inputs(['id']);

        $this->validate($params, [
            'id' => 'required',
        ]);
        return $this->success(['url' => $this->talkSessionService->download($this->uid(),$params['id'])]);
    }

    /**
     * 机器人列表排序
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('sort')]
    public function sort(): ResponseInterface
    {
        $params = $this->request->inputs(['source_id','target_id']);

        $this->validate($params, [
            'source_id' => 'required',
            'target_id' => 'required',
        ]);

        return $this->talkSessionService->sort($this->uid(),$params['source_id'],$params['target_id'])
            ? $this->success('排序成功')
            : $this->error('排序失败');
    }

    /**
     * 修改群名称
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('modifyRoomName')]
    public function modifyRoomName(): ResponseInterface
    {
        $params = $this->request->inputs(['id','room_name']);

        $this->validate($params, [
            'id' => 'required',
            'room_name' => 'required|max:120',
        ]);

        return $this->talkSessionService->modifyRoomName($this->uid(),$params['id'],$params['room_name'])
            ? $this->success()
            : $this->error();
    }

    /**
     * 添加好友
     * @return ResponseInterface
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    #[PostMapping('addFriend')]
    public function addFriend(): ResponseInterface
    {
        $params = $this->request->inputs(['id','verify_text']);

        $this->validate($params, [
            'id' => 'required',
            'verify_text' => 'max:120',
        ]);

        return $this->talkSessionService->addFriend($this->uid(),$params['id'],$params['verify_text'] ?? '')
            ? $this->success()
            : $this->error();
    }
}
